package lnet

import (
	"fmt"
	"linx/liface"
	"linx/utils"
)

type MsgHandler struct {
	// 存在每个业务msgid所对应的处理方法
	Apis map[uint32]liface.IRouter

	// 负责worker的消息队列
	TaskQueue []chan liface.IRequest

	// 业务工作worker池的worker数量
	WorkerPoolSize uint32
}

func NewMsgHandle() *MsgHandler {
	return &MsgHandler{
		Apis:           make(map[uint32]liface.IRouter),
		WorkerPoolSize: utils.GlobalObject.WorkPoolSize, // 从全局配置文件中获取
		TaskQueue:      make([]chan liface.IRequest, utils.GlobalObject.WorkPoolSize),
	}
}

// 调度/执行对应的Router消息处理方法
func (m *MsgHandler) DoMsgHandler(request liface.IRequest) {
	handler, ok := m.Apis[request.GetMsgID()]
	if !ok {
		fmt.Printf("api msgID:%d is not found!\n", request.GetMsgID())
		return
	}
	handler.PreHandle(request)
	handler.Handle(request)
	handler.PostHandle(request)
}

// 为消息添加具体的处理器逻辑
func (m *MsgHandler) AddRouter(msgID uint32, router liface.IRouter) {
	// 1. 判断是否重复
	if _, ok := m.Apis[msgID]; ok {
		fmt.Println("Add router repeat msgID:", msgID)
		return
	}
	// 2. 添加msg和API绑定的关系
	m.Apis[msgID] = router
	fmt.Println("Add router success msgID:", msgID)
}

// 启动一个 Worker 工作池 （开启工作池的动作只能发生一次，一个linx框架只能有一个工作池）
func (m *MsgHandler) StartWorkerPool() {
	// 根据workerPoolSize 分别开启 Worker 每个 Worker用一个go来承载
	for i := 0; i < int(m.WorkerPoolSize); i++ {
		// 一个 worker 被启动
		// 1. 当前的 worker对应的channel消息队列 开辟空间 第0个worker就用第0个channel
		m.TaskQueue[i] = make(chan liface.IRequest, utils.GlobalObject.MaxWorkerTaskLen)
		// 2. 启动当前 worker，阻塞等到消息从 channel 传递过来
		go m.startOneWorker(i, m.TaskQueue[i])
	}
}

// 启动一个 Worker 工作流程队列
func (m *MsgHandler) startOneWorker(workerID int, taskQueue chan liface.IRequest) {
	fmt.Printf("Work ID=%d is start!\n", workerID)

	// 不断的阻塞等待对应消息队列的消息
	for {
		select {
		case request := <-taskQueue:
			m.DoMsgHandler(request)
		}
	}
}

// 将消息交给TaskQueue 由Worker进行处理
func (m *MsgHandler) SendMsgTaskQueue(request liface.IRequest) {
	// 1. 将消息平局分配给不同 worker
	workID := request.GetConnection().GetConnID() % m.WorkerPoolSize
	fmt.Printf("Add ConnID=%d request MsgID=%d to WorkerID=%d\n", request.GetConnection().GetConnID(), request.GetMsgID(), workID)

	// 2. 将消息发送给对应的worker的TaskQueue
	m.TaskQueue[workID] <- request
}
